﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace AmiEmuLib.Native
{
    public static class NativeSetupDevice
    {
        /// <summary>
        /// A variable of type DWORD that specifies control options that filter the device 
        /// information elements that are added to the device information set. 
        /// </summary>
        [Flags]
        public enum SetupDiGetClassDevsFlags : uint
        {
            /// <summary>
            /// Return only the device that is associated with the system default device interface, 
            /// if one is set, for the specified device interface classes. 
            /// </summary>
            DIGCF_DEFAULT = 0x00000001,
            /// <summary>
            /// Return only devices that are currently present in a system. 
            /// </summary>
            DIGCF_PRESENT = 0x00000002,
            /// <summary>
            /// Return a list of installed devices for all device setup classes or all 
            /// device interface classes. 
            /// </summary>
            DIGCF_ALLCLASSES = 0x00000004,
            /// <summary>
            /// Return only devices that are a part of the current hardware profile. 
            /// </summary>
            DIGCF_PROFILE = 0x00000008,
            /// <summary>
            /// Return devices that support device interfaces for the specified device interface 
            /// classes. This flag must be set in the Flags parameter if the Enumerator parameter 
            /// specifies a device instance ID.
            /// </summary>
            DIGCF_DEVICEINTERFACE = 0x00000010,
        }

        /// <summary>
        /// The SetupDiGetClassDevs function returns a handle to a device information set that 
        /// contains requested device information elements for a local computer. 
        /// </summary>
        /// <param name="ClassGuid">
        /// A pointer to the GUID for a device setup class or a device interface class. 
        /// This pointer is optional and can be NULL.
        /// </param>
        /// <param name="Enumerator">
        /// A pointer to a NULL-terminated string that specifies:
        /// 
        /// An identifier (ID) of a Plug and Play (PnP) enumerator. This ID can either be the 
        /// value's globally unique identifier (GUID) or symbolic name. For example, "PCI" 
        /// can be used to specify the PCI PnP value. Other examples of symbolic names for 
        /// PnP values include "USB," "PCMCIA," and "SCSI".
        /// 
        /// A PnP device instance ID. When specifying a PnP device instance ID, DIGCF_DEVICEINTERFACE 
        /// must be set in the Flags parameter.
        /// 
        /// This pointer is optional and can be NULL. If an enumeration value is not used to select 
        /// devices, set Enumerator to NULL 
        /// </param>
        /// <param name="hwndParent">
        /// A handle to the top-level window to be used for a user interface that is 
        /// associated with installing a device instance in the device information set. This handle is optional and can be NULL.
        /// </param>
        /// <param name="Flags">
        /// A variable of type DWORD that specifies control options that filter the device 
        /// information elements that are added to the device information set. 
        /// </param>
        /// <returns>
        /// If the operation succeeds, SetupDiGetClassDevs returns a handle to a device 
        /// information set that contains all installed devices that matched the supplied 
        /// parameters. If the operation fails, the function returns INVALID_HANDLE_VALUE. 
        /// To get extended error information, call GetLastError. 
        /// </returns>
        [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern IntPtr SetupDiGetClassDevs
        (
            ref Guid ClassGuid,
            string Enumerator,
            IntPtr hwndParent,
            SetupDiGetClassDevsFlags Flags
        );

        /// <summary>
        /// The SetupDiGetClassDevs function returns a handle to a device information set that 
        /// contains requested device information elements for a local computer. 
        /// </summary>
        /// <param name="Null">
        /// A pointer to the GUID for a device setup class or a device interface class. 
        /// Should be IntPtr.Zero.
        /// </param>
        /// <param name="Enumerator">
        /// A pointer to the GUID for a device setup class or a device interface class. 
        /// This pointer is optional and can be NULL.
        /// A pointer to a NULL-terminated string that specifies:
        /// 
        /// An identifier (ID) of a Plug and Play (PnP) enumerator. This ID can either be the 
        /// value's globally unique identifier (GUID) or symbolic name. For example, "PCI" 
        /// can be used to specify the PCI PnP value. Other examples of symbolic names for 
        /// PnP values include "USB," "PCMCIA," and "SCSI".
        /// 
        /// A PnP device instance ID. When specifying a PnP device instance ID, DIGCF_DEVICEINTERFACE 
        /// must be set in the Flags parameter.
        /// 
        /// This pointer is optional and can be NULL. If an enumeration value is not used to select 
        /// devices, set Enumerator to NULL 
        /// </param>
        /// <param name="hwndParent">
        /// A handle to the top-level window to be used for a user interface that is 
        /// associated with installing a device instance in the device information set. This handle is optional and can be NULL.
        /// </param>
        /// <param name="Flags">
        /// A variable of type DWORD that specifies control options that filter the device 
        /// information elements that are added to the device information set. Should be set to 
        /// NativeSetupDevice.SetupDiGetClassDevsFlags.DIGCF_ALLCLASSES.
        /// </param>
        /// <returns>
        /// If the operation succeeds, SetupDiGetClassDevs returns a handle to a device 
        /// information set that contains all installed devices that matched the supplied 
        /// parameters. If the operation fails, the function returns INVALID_HANDLE_VALUE. 
        /// To get extended error information, call GetLastError. 
        /// </returns>
        [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern IntPtr SetupDiGetClassDevs
        (
            IntPtr Null,
            string Enumerator,
            IntPtr hwndParent,
            SetupDiGetClassDevsFlags Flags /*= NativeSetupDevice.SetupDiGetClassDevsFlags.DIGCF_ALLCLASSES */
        );

        /// <summary>
        /// An SetupDevInfoData structure defines a device instance that is a member of a 
        /// device information set.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct SetupDeviceInfoData
        {
            public static readonly uint StructSize =
                (uint)Marshal.SizeOf(typeof(SetupDeviceInfoData));

            /// <summary>
            /// The size, in bytes, of the SetupDevInfoData structure. 
            /// For more information, see the following Remarks section.
            /// </summary>
            public uint Size;
            /// <summary>
            /// The GUID of the device's setup class.
            /// </summary>
            public Guid ClassGuid;
            /// <summary>
            /// An opaque handle to the device instance (also known as a handle to the devnode).
            /// 
            /// Some functions, such as SetupDiXxx functions, take the whole SetupDevInfoData 
            /// structure as input to identify a device in a device information set. 
            /// Other functions, such as CM_Xxx functions like CM_Get_DevNode_Status, 
            /// take this DevInst handle as input.
            /// </summary>
            public uint DevInst;
            /// <summary>
            /// Reserved. For internal use only.
            /// </summary>
            public IntPtr Reserved;
        }

        /// <summary>
        /// The SetupDiEnumDeviceInfo function returns a SetupDevInfoData structure that 
        /// specifies a device information element in a device information set. 
        /// </summary>
        /// <param name="DeviceInfoSet">
        /// A handle to the device information set for which to return an 
        /// SetupDevInfoData structure that represents a device information element.
        /// Returned by SetupDiGetClassDevs().
        /// </param>
        /// <param name="MemberIndex">
        /// A zero-based index of the device information element to retrieve.
        /// </param>
        /// <param name="DeviceInfoData">
        /// A pointer to an SetupDevInfoData structure to receive information about an 
        /// enumerated device information element. The caller must set DeviceInfoData.Size 
        /// to size of SetupDevInfoData.
        /// </param>
        /// <returns>
        /// The function returns TRUE if it is successful. Otherwise, it returns FALSE 
        /// and the logged error can be retrieved with a call to GetLastError.
        /// </returns>
        [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool SetupDiEnumDeviceInfo
        (
            IntPtr DeviceInfoSet,
            uint MemberIndex,
            ref SetupDeviceInfoData DeviceInfoData
        );

        /// <summary>
        /// The SetupDiGetDeviceInstanceId function retrieves the device instance ID that 
        /// is associated with a device information element.
        /// </summary>
        /// <param name="DeviceInfoSet">
        /// A handle to the device information set that contains the device information element 
        /// that represents the device for which to retrieve a device instance ID. 
        /// Returned by SetupDiGetClassDevs().
        /// </param>
        /// <param name="DeviceInfoData">
        /// A pointer to an SetupDeviceInfoData structure that specifies the device information 
        /// element in DeviceInfoSet. Returned by SetupDiEnumDeviceInfo().
        /// </param>
        /// <param name="DeviceInstanceId">
        /// A pointer to the character buffer that will receive the NULL-terminated device 
        /// instance ID for the specified device information element. 
        /// </param>
        /// <param name="DeviceInstanceIdSize">
        /// The size, in characters, of the DeviceInstanceId buffer.
        /// </param>
        /// <param name="RequiredSize">
        /// A pointer to the variable that receives the number of characters required 
        /// to store the device instance ID.
        /// </param>
        /// <returns>
        /// The function returns TRUE if it is successful. Otherwise, 
        /// it returns FALSE and the logged error can be retrieved by making a call to GetLastError.
        /// </returns>
        [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool SetupDiGetDeviceInstanceId
        (
           IntPtr DeviceInfoSet,
           ref SetupDeviceInfoData DeviceInfoData,
           StringBuilder DeviceInstanceId,
           uint DeviceInstanceIdSize,
           out uint RequiredSize
        );

        /// <summary>
        /// The SetupDiGetDeviceInstanceId function retrieves the device instance ID that 
        /// is associated with a device information element.
        /// </summary>
        /// <param name="DeviceInfoSet">
        /// A handle to the device information set that contains the device information element 
        /// that represents the device for which to retrieve a device instance ID. 
        /// Returned by SetupDiGetClassDevs().
        /// </param>
        /// <param name="DeviceInfoData">
        /// A pointer to an SetupDeviceInfoData structure that specifies the device information 
        /// element in DeviceInfoSet. Returned by SetupDiEnumDeviceInfo().
        /// </param>
        /// <param name="Null">
        /// A pointer to the character buffer that will receive the NULL-terminated device 
        /// instance ID for the specified device information element. 
        /// </param>
        /// <param name="DeviceInstanceIdSize">
        /// The size, in characters, of the DeviceInstanceId buffer.
        /// </param>
        /// <param name="RequiredSize">
        /// A pointer to the variable that receives the number of characters required 
        /// to store the device instance ID.
        /// </param>
        /// <returns>
        /// The function returns TRUE if it is successful. Otherwise, 
        /// it returns FALSE and the logged error can be retrieved by making a call to GetLastError.
        /// </returns>
        [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool SetupDiGetDeviceInstanceId
        (
           IntPtr DeviceInfoSet,
           ref SetupDeviceInfoData DeviceInfoData,
           IntPtr Null,
           uint DeviceInstanceIdSize,
           out uint RequiredSize
        );

        /// <summary>
        /// Flags for SetupDiGetDeviceRegistryProperty().
        /// </summary>
        public enum SetupDiGetDeviceRegistryPropertyEnum : uint
        {
            SPDRP_DEVICEDESC = 0x00000000, // DeviceDesc (R/W)
            SPDRP_HARDWAREID = 0x00000001, // HardwareID (R/W)
            SPDRP_COMPATIBLEIDS = 0x00000002, // CompatibleIDs (R/W)
            SPDRP_UNUSED0 = 0x00000003, // unused
            SPDRP_SERVICE = 0x00000004, // Service (R/W)
            SPDRP_UNUSED1 = 0x00000005, // unused
            SPDRP_UNUSED2 = 0x00000006, // unused
            SPDRP_CLASS = 0x00000007, // Class (R--tied to ClassGUID)
            SPDRP_CLASSGUID = 0x00000008, // ClassGUID (R/W)
            SPDRP_DRIVER = 0x00000009, // Driver (R/W)
            SPDRP_CONFIGFLAGS = 0x0000000A, // ConfigFlags (R/W)
            SPDRP_MFG = 0x0000000B, // Mfg (R/W)
            SPDRP_FRIENDLYNAME = 0x0000000C, // FriendlyName (R/W)
            SPDRP_LOCATION_INFORMATION = 0x0000000D, // LocationInformation (R/W)
            SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = 0x0000000E, // PhysicalDeviceObjectName (R)
            SPDRP_CAPABILITIES = 0x0000000F, // Capabilities (R)
            SPDRP_UI_NUMBER = 0x00000010, // UiNumber (R)
            SPDRP_UPPERFILTERS = 0x00000011, // UpperFilters (R/W)
            SPDRP_LOWERFILTERS = 0x00000012, // LowerFilters (R/W)
            SPDRP_BUSTYPEGUID = 0x00000013, // BusTypeGUID (R)
            SPDRP_LEGACYBUSTYPE = 0x00000014, // LegacyBusType (R)
            SPDRP_BUSNUMBER = 0x00000015, // BusNumber (R)
            SPDRP_ENUMERATOR_NAME = 0x00000016, // Enumerator Name (R)
            SPDRP_SECURITY = 0x00000017, // Security (R/W, binary form)
            SPDRP_SECURITY_SDS = 0x00000018, // Security (W, SDS form)
            SPDRP_DEVTYPE = 0x00000019, // Device Type (R/W)
            SPDRP_EXCLUSIVE = 0x0000001A, // Device is exclusive-access (R/W)
            SPDRP_CHARACTERISTICS = 0x0000001B, // Device Characteristics (R/W)
            SPDRP_ADDRESS = 0x0000001C, // Device Address (R)
            SPDRP_UI_NUMBER_DESC_FORMAT = 0X0000001D, // UiNumberDescFormat (R/W)
            SPDRP_DEVICE_POWER_DATA = 0x0000001E, // Device Power Data (R)
            SPDRP_REMOVAL_POLICY = 0x0000001F, // Removal Policy (R)
            SPDRP_REMOVAL_POLICY_HW_DEFAULT = 0x00000020, // Hardware Removal Policy (R)
            SPDRP_REMOVAL_POLICY_OVERRIDE = 0x00000021, // Removal Policy Override (RW)
            SPDRP_INSTALL_STATE = 0x00000022, // Device Install State (R)
            SPDRP_LOCATION_PATHS = 0x00000023, // Device Location Paths (R)
            SPDRP_BASE_CONTAINERID = 0x00000024  // Base ContainerID (R)
        }

        /// <summary>
        /// The SetupDiGetDeviceRegistryProperty function retrieves a specified Plug and Play 
        /// device property.
        /// </summary>
        /// <param name="DeviceInfoSet">
        /// A handle to a device information set that contains a device information element 
        /// that represents the device for which to retrieve a Plug and Play property.
        /// Returned by SetupDiGetClassDevs().
        /// </param>
        /// <param name="DeviceInfoData">
        /// A pointer to an SetupDeviceInfoData structure that specifies the device information 
        /// element in DeviceInfoSet. Returned y SetupDiEnumDeviceInfo().
        /// </param>
        /// <param name="Property">
        /// Property to be retrieved.
        /// </param>
        /// <param name="PropertyRegDataType">
        /// A pointer to a variable that receives the data type of the property that is 
        /// being retrieved. This is one of the standard registry data types. This parameter 
        /// is optional and can be NULL.
        /// </param>
        /// <param name="PropertyBuffer">
        /// A pointer to a buffer that receives the property that is being retrieved. If 
        /// this parameter is set to NULL, and PropertyBufferSize is also set to zero, the 
        /// function returns the required size for the buffer in RequiredSize.
        /// </param>
        /// <param name="PropertyBufferSize">
        /// The size, in bytes, of the PropertyBuffer buffer.
        /// </param>
        /// <param name="RequiredSize">
        /// A pointer to a variable of type DWORD that receives the required size, in bytes, of 
        /// the PropertyBuffer buffer that is required to hold the data for the requested property. 
        /// This parameter is optional and can be NULL.
        /// </param>
        /// <returns>
        /// SetupDiGetDeviceRegistryProperty returns TRUE if the call was successful. Otherwise, it 
        /// returns FALSE and the logged error can be retrieved by making a call to GetLastError. 
        /// SetupDiGetDeviceRegistryProperty returns the ERROR_INVALID_DATA error code if the 
        /// requested property does not exist for a device or if the property data is not valid.
        /// </returns>
        [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool SetupDiGetDeviceRegistryProperty
        (
            IntPtr DeviceInfoSet,
            ref SetupDeviceInfoData DeviceInfoData,
            SetupDiGetDeviceRegistryPropertyEnum Property,
            out uint PropertyRegDataType,
            IntPtr PropertyBuffer,
            uint PropertyBufferSize,
            out uint RequiredSize
         );

        /// <summary>
        /// The SetupDiGetDeviceRegistryProperty function retrieves a specified Plug and Play 
        /// device property.
        /// </summary>
        /// <param name="DeviceInfoSet">
        /// A handle to a device information set that contains a device information element 
        /// that represents the device for which to retrieve a Plug and Play property.
        /// Returned by SetupDiGetClassDevs().
        /// </param>
        /// <param name="DeviceInfoData">
        /// A pointer to an SetupDeviceInfoData structure that specifies the device information 
        /// element in DeviceInfoSet. Returned by SetupDiEnumDeviceInfo().
        /// </param>
        /// <param name="Property">
        /// Property to be retrieved.
        /// </param>
        /// <param name="PropertyRegDataType">
        /// A pointer to a variable that receives the data type of the property that is 
        /// being retrieved. This is one of the standard registry data types. This parameter 
        /// is optional and can be NULL.
        /// </param>
        /// <param name="PropertyBuffer">
        /// A pointer to a buffer that receives the property that is being retrieved. If 
        /// this parameter is set to NULL, and PropertyBufferSize is also set to zero, the 
        /// function returns the required size for the buffer in RequiredSize.
        /// </param>
        /// <param name="PropertyBufferSize">
        /// The size, in bytes, of the PropertyBuffer buffer.
        /// </param>
        /// <param name="RequiredSize">
        /// A pointer to a variable of type DWORD that receives the required size, in bytes, of 
        /// the PropertyBuffer buffer that is required to hold the data for the requested property. 
        /// This parameter is optional and can be NULL.
        /// </param>
        /// <returns>
        /// SetupDiGetDeviceRegistryProperty returns TRUE if the call was successful. Otherwise, it 
        /// returns FALSE and the logged error can be retrieved by making a call to GetLastError. 
        /// SetupDiGetDeviceRegistryProperty returns the ERROR_INVALID_DATA error code if the 
        /// requested property does not exist for a device or if the property data is not valid.
        /// </returns>
        [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool SetupDiGetDeviceRegistryProperty
        (
            IntPtr DeviceInfoSet,
            ref SetupDeviceInfoData DeviceInfoData,
            SetupDiGetDeviceRegistryPropertyEnum Property,
            out uint PropertyRegDataType,
            StringBuilder PropertyBuffer,
            uint PropertyBufferSize,
            out uint RequiredSize
         );

        /// <summary>
        /// The SetupDiDestroyDeviceInfoList function deletes a device information set and 
        /// frees all associated memory.
        /// </summary>
        /// <param name="DeviceInfoData">
        /// A handle to the device information set to delete. Returned y SetupDiEnumDeviceInfo().
        /// </param>
        /// <returns>
        /// The function returns TRUE if it is successful. Otherwise, it returns 
        /// FALSE and the logged error can be retrieved with a call to GetLastError.
        /// </returns>
        [DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern bool SetupDiDestroyDeviceInfoList
        (
            IntPtr DeviceInfoData
        );
    }
}
